﻿#define _CRT_SECURE_NO_WARNINGS


//malloc函数的使用
#include<stdio.h>
#include<stdlib.h>//malloc所涉及的头文件
//int main()
//{
//	//int arr[10] = { 0 };//开辟的空间不可以更改，固定死了
//	//void* malloc (size_t size)  size的单位是字节
//	//malloc函数只知道申请空间，不知道返回类型是什么
//	int* p=(int*)malloc(40);//向内存申请40个字节的空间，他的返回值是void*
//	//强制类型转换成int*后，再赋值给指针变量p，就相当于int arr[10]
//	if (p == NULL)//判断p指针是否为空
//	{
//		perror("malloc");
//		return 1;
//	}
//	//访问并使用malloc开辟的空间
//	for (int i = 0; i < 10; i++)
//	{
//		*(p+i)=i;
//	}
//	//打印
//	for (int i = 0; i < 10; i++)
//	{
//		printf("%d " ,* (p + i));
//	}
//	//释放空间
//	free(p);
//	p = NULL;//用free释放空间后，空间释放了，但p仍然记得地址起始位置
//	//避免p变为野指针，将p设为NULL
//	return 0;
//}
//malloc 申请的空间是在内存的堆区

//int main()
//{//                  元素个数，元素大小
//	int* p = (int*)calloc(10,sizeof(int));
//	if (p == NULL)//判断p指针是否为空
//	{
//		perror("calloc");
//		return 1;
//	}
//	//calloc函数会将值全部初始化为0
//	//打印
//	for (int i = 0; i < 10; i++)
//	{
//		printf("%d ", *(p + i));
//	}
//
//}
//realloc函数开辟空间有两种情况
//1.原空间后面有足够的空间，直接扩大，返回原空间的起始地址
//2.原空间后面没有足够的空间，realloc会在堆区重新找一个空间（满足需求的）
//并且把原数据拷贝到新的空间，然后释放旧的空间，同时返回新空间的起始位置
//#include<stdio.h>
//#include<stdlib.h>
//int main()
//{
//	//void* malloc (size_t size)  size的单位是字节
//	//malloc函数只知道申请空间，不知道返回类型是什么
//	int* p=(int*)malloc(40);//向内存申请40个字节的空间，他的返回值是void*
//	//强制类型转换成int*后，再赋值给指针变量p，就相当于int arr[10]
//	if (p == NULL)//判断p指针是否为空
//	{
//		perror("malloc");
//		return 1;
//	}
//	//若空间不够，想要扩大空间,20个整形
////参数：（指针，想要变成的大小）
//	int* ptr = (int*)realloc(p, 20 * sizeof(int));
//	if (ptr != NULL)//先把判断ptr是否为空指针，再把ptr赋值给p
//	{//若直接用p接收，若开辟空间失败，p会被置为NULL,造成原空间找不到了
//		p = ptr;
//	}
//	else
//	{
//		perror("realloc");
//	}
////	realloc函数不会初始化空间
////	使用空间
//	for (int i = 0; i < 20; i++)
//	{
//		*(p+i)=i;
//	}
//	//打印
//	for (int i = 0; i < 20; i++)
//	{
//		printf("%d " ,* (p + i));
//	}
//	//释放空间
//	free(p);
//	p = NULL;//用free释放空间后，空间释放了，但p仍然记得地址起始位置
//	//避免p变为野指针，将p设为NULL
//	return 0;
//}

////与malloc函数的联系
//int main()
//{
//	int* p = (int*)realloc(NULL, 40);//等价于malloc
//	return 0;
//}
//对NULL指针解引用
//int main()
//{
//	int* p = (int*)malloc(100);
//	if (p == NULL)
//	{
//		//报错信息
//		perror("malloc");
//		return 1;
//	}
//	*p = 20;//p有可能是NULL指针
//	//释放
//	free(p);
//	p = NULL;
//	return 0;
//}

//int main()
//{
//	int *p=(int*)malloc(40);
//	if (p == NULL)
//	{
//		return 1;
//	}
//	//使用
//	for (int i = 0; i < 10; i++)
//	{
//		*(p + i) = i;//当访问第11个元素时，就越界访问了
//	}
//	free(p);
//	p = NULL;
//	return 0;
//}
//3 对⾮动态开辟内存使⽤free释放
//int main()
//{
//	int a = 10;//⾮动态开辟内存
//	int* p = (int*)malloc(40);
//	if (p == NULL)
//	{
//		return 1;
//	}
//	//使用
//	//……
//	p = &a;//p指向的空间不再是堆区上空间了
//	free(p);
//	p = NULL;
//	return 0;
//}
//malloc、calloc、realloc申请的空间如果不主动释放，出了作用域不会销毁
//释放的方式
//1.free主动释放
//2.直到程序结束，由操作系统回收
//malloc函数出了test函数申请的空间不会销毁
//int* test()
//{
//	int* p = (int*)malloc(40);
	/*if (p == NULL)
	{
		return 1;*/
//	}
//	else
//		return 0;
//}
//int main()
//{
//
//}
//4 使⽤free释放⼀块动态开辟内存的⼀部分

//5. 对同⼀块动态内存多次释放
//void test()
//{
//	int* p = (int*)malloc(100);
//	if (p == NULL)
//	{
//		return 1;
//	}
//	free(p);
//	p = NULL;
//	free(p);//重复释放 
//	p = NULL;
//}
////动态开辟内存忘记释放（内存泄漏）
//void test()
//{
//	int* p = (int*)malloc(100);
//	if (NULL != p)
//	{
//		*p = 20;
//	}
//	free(p);
//	p = NULL;
//}
//
//int main()
//{
//	test();
//	while (1);
//}
//柔性数组
//在结构体中，最后一个成员是大小未知的数组
//struct st_type
//{
//	int i;//柔性数组前面至少要有一个其他成员
//	int a[0];//柔性数组成员
//	//int a[];
//};
//int main()
//{
//	printf("%d\n", sizeof(struct st_type));
//	return 0;
//}
//struct st
//{
//	int a;
//	int arr[];
//};
//使用柔性数组，只是用了一次malloc函数，减少了内存碎片
//int main()
//{//用结构体指针变量ps接收malloc函数分配空间的地址
//	struct st*ps=(struct st*)malloc(sizeof(struct st) + 10 * sizeof(int));
//	//              malloc分配空间的大小是 结构体大小+40字节 （40字节是分配给柔性数组的）
//	//判断
//	if (ps == NULL)
//	{
//		return 1;
//	}
//	//使用
//	ps->a = 100;
//	for (int i = 0; i < 10; i++)
//	{
//		ps->arr[i] = i;
//	}
//	//若数组空间不够
//	//用realloc函数重新分配
//	struct st*ptr=(struct st*)realloc(ps,sizeof(struct st) + 15 * sizeof(int));
//	if (ptr != NULL)
//	{
//		ps = ptr;//再次赋值给ps
//	}
//	else
//	{
//		perror("realloc");
//	}
//	//继续使用
//	for (int i = 0; i < 15; i++)
//	{
//		ps->arr[i] = i;
//	}
//	//打印
//	for (int i = 0; i < 15; i++)
//	{
//		printf("%d ",ps->arr[i]);
//	}
//	//释放
//	free(ps);
//	ps = NULL;
//
//
//	return 0;
//}
//不使用柔性数组，就要多次使用malloc函数开辟空间
struct st
{
	int a;
	int* arr;
};
int main()
{//用结构体指针变量ps接收malloc函数分配空间的地址
	struct st* ps = (struct st*)malloc(sizeof(struct st));
	//判断
	if (ps == NULL)
	{
		return 1;
	}
	//使用
	ps->a = 100;
	//再次使用malloc函数给数组arr开辟空间
	ps->arr = (int*)malloc(10 * sizeof(int));
	if (ps->arr == NULL)
	{
		perror("malloc-2");
		return 1;
	}
	//使用
	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	//数组空间不够
	// 利用realloc函数扩大
	int* ptr=(int*)realloc(ps->arr, 15 * sizeof(int));
	if (ptr == NULL)
	{
		perror("realloc");
		return 1;
	}
	else
	{
		ps->arr  = ptr;
	}
	//打印
	for (int i = 0; i < 15; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//释放
	free(ps->arr);
	ps->arr = NULL;
	free(ps);
	ps = NULL;
	return 0;
}

//内存池：减少了大量的内存创建和释放，减少内存碎片
//CPU运行速度：寄存器、缓存、内存、硬盘，速度逐渐增加